/**
 * @file Acceptor.cc
 * @author zziywang (zziywang@163.com)
 * @brief { life is too short to learn cpp! }
 * @version 1.0
 * @date 2022-05-07
 *
 * @copyright Copyright (c) 2022
 *
 */

#include "Acceptor.hh"
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>

namespace snow
{

Acceptor::Acceptor(const string &ip, unsigned short port)
    : addr_(ip, port),
      listenSock_() {}

Acceptor::Acceptor(unsigned short port)
    : addr_(port),
      listenSock_() {}

Acceptor::Acceptor(const sockaddr_in addr)
    : addr_(addr),
      listenSock_() {}

void Acceptor::ready()
{
    setAddrReuse(true);
    setPortReuse(true);
    bind();
    listen(10);
}

void Acceptor::bind()
{
    int ret = ::bind(listenSock_.getFd(), (struct sockaddr *)addr_.getAddr(), sizeof(struct sockaddr));
    if (-1 == ret) {
        perror("bind");
    }
}
void Acceptor::listen(int backlog)
{
    // 已经连接队列(处于ESTABLISHED且在accept之前的连接)的最大长度取决于
    // max{ listen()中的backlog参数， /proc/sys/net/core/somaxconn值 }
    int ret = ::listen(listenSock_.getFd(), backlog);
    if (-1 == ret) {
        perror("listen");
    }
}
int Acceptor::accept()
{
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    socklen_t len = sizeof(struct sockaddr);
    int peerfd = ::accept(listenSock_.getFd(), (struct sockaddr *)&client, &len);
    if (-1 == peerfd) {
        perror("accept");
    }
    return peerfd;
}

void Acceptor::setPortReuse(bool flag)
{
    int on = flag;
    int ret = ::setsockopt(listenSock_.getFd(), SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
    if (-1 == ret) {
        perror("setsockopt reuse port");
    }
}
void Acceptor::setAddrReuse(bool flag)
{
    int on = flag;
    int ret = ::setsockopt(listenSock_.getFd(), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    if (-1 == ret) {
        perror("setsockopt reuse addr");
    }
}
// v2新增：获取服务器sockfd，注册进epoll
int Acceptor::getSockFd() const
{
    return listenSock_.getFd();
}

} // namespace snow